package leetcode.concurrency;

import java.util.concurrent.Semaphore;

/**
 * H20生成
 * @author jiangwz
 * @create 2019/11/6.
 */
public class Q1117 {
    public static void main(String[] args) {
        int n = 4;

        H2O h2O = new H2O();
        for (int i = 0; i < 2 * n; i++) {
            new Thread(() -> {
                try {
                    h2O.hydrogen(() -> System.out.print("H"));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "1").start();

        }
        for (int i = 0; i < n; i++) {
            new Thread(() -> {
                try {
                    h2O.oxygen(() -> System.out.print("O"));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "2").start();

        }

    }
}

class H2O {


    Semaphore s1,s2,s3,s4 = null;


    public H2O() {
        s1 = new Semaphore(2); //h
        s2 = new Semaphore(1);//o

        s3 = new Semaphore(0);// h1
        s4 = new Semaphore(0);// o2
    }

    public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
        s1.acquire(); //这里可以并发2个线程
        s4.acquire(); // 获取1个O信号 (等着s4释放O信号,只要O信号释放,立马并发执行下面的H信号释放,接着并发输出H)
        s3.release(); // 释放1个H信号
        // releaseHydrogen.run() outputs "H". Do not change or remove this line.
        releaseHydrogen.run();
        s1.release();
    }

    public void oxygen(Runnable releaseOxygen) throws InterruptedException {
        // releaseOxygen.run() outputs "O". Do not change or remove this line.
        s2.acquire();//这里只能并发一个线程
        s4.release(2);// 释放2个o信号
        s3.acquire(2); // 等待获取2个H信号 (只要有2个H信号释放,立马输出O, 具体先输出O还是H,看谁先抢到)
        releaseOxygen.run();
        s2.release();
    }
}


// 这代码是真的秀
//class H2O {
//
//    private Semaphore s1,s2,s3,s4;
//
//    public H2O() {
//        s1 = new Semaphore(2); // H线程信号量
//        s2 = new Semaphore(1); // O线程信号量
//
//        s3 = new Semaphore(0); // H反应条件信号量
//        s4 = new Semaphore(0); // O反应条件信号量
//    }
//
//    public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
//        s1.acquire(); // 保证只有2个H线程进入执行
//        s3.release(); // 释放H原子到达信号
//        s4.acquire(); // 等待O原子到达
//        releaseHydrogen.run();
//        s1.release(); // 相当于唤醒1个H线程
//    }
//
//    public void oxygen(Runnable releaseOxygen) throws InterruptedException {
//        s2.acquire(); // 保证只有1个O线程进入执行
//        s4.release(2); // 释放O原子到达信号，因为有2个H线程等待所以释放2个
//        s3.acquire(2); // 等待H原子到达，2个原因同上
//        releaseOxygen.run();
//        s2.release(); // 相当于唤醒1个O线程
//    }
//}